home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
CU Amiga Super CD-ROM 21
/
CU Amiga Magazine's Super CD-ROM 21 (1998)(EMAP Images)(GB)[!][issue 1998-04].iso
/
CUCD
/
Programming
/
Python-1.4
/
Python1.4_Source
/
Modules
/
arexxmodule.c
< prev
next >
Wrap
C/C++ Source or Header
|
1997-01-01
|
20KB
|
899 lines
/********************************************************************
Lowlevel Amiga ARexx module.
Provides `arexxport' object, which is a opened ARexx port.
The port returns `arexxmsg' objects.
-----------------------------------------------
(c) 1996 Irmen de Jong.
History:
20-may-96 Created.
25-may-96 Major overhaul; now uses arexxmsg objects.
27-may-96 Added ReadArgs function.
8-jun-96 Rewrote ReadArgs.
9-jun-96 Moved ReadArgs to doslibmodule.
26-aug-96 Added message.getvar().
Module members:
error -- Exeption string object. ('arexx.error')
port -- function returning a new ARexx port object.
port = arexxll.port('PORTNAME')
errorstring -- returns string associated with arexx error code.
ARexxPort object members:
name -- attribute, name of the port (RO)
signal -- attribute, signal mask of the MsgPort's sigbit (RO)
close -- function, closes the port
wait -- function, waits for message to arrive
getmsg -- function, returns ARexxMessage object, or None.
send -- function, to send command to other port
send(to,cmd,async?) returns (rc,rc2,result) if synchronous.
ARexxMessage object members:
reply -- function, replies the message with the given results
Each message must be replied to!
setvar -- function, sets ARexx variable
getvar -- function, extracts ARexx variable
wantresult -- attribute, does the message require a result string? (BOOL, RO)
msg -- attribute, the message itself (string) (RO)
rc -- attribute, result code for reply() (integer)
rc2 -- attribute, secondary result code (string or None)
result -- attribute, result string (string or None)
**************************************************************************/
#include <stdlib.h>
#include <dos.h>
#include <exec/types.h>
#include <exec/memory.h>
#include <dos/dos.h>
#include <exec/libraries.h>
#include <rexx/storage.h>
#include <rexx/rxslib.h>
#include <proto/dos.h>
#include <proto/exec.h>
#include <proto/rexxsyslib.h>
#include <clib/alib_protos.h>
#include "allobjects.h"
#include "modsupport.h"
#define ARB_HF_CMDSHELL (1L << 0)
#define ARB_HF_USRMSGPORT (1L << 1)
#define ARB_HF_NOTPUBLIC (1L << 2)
#define toupper(c) (c&(~32))
struct RexxHost
{
struct MsgPort *port;
char portname[ 80 ];
long replies;
long flags;
APTR userdata;
};
typedef struct {
PyObject_HEAD
struct RexxHost *host;
ULONG signal;
} arexxportobject;
typedef struct {
PyObject_HEAD
struct RexxMsg *msg;
BOOL replied; // has this message been replied to yet?
int rc; // primary return code (RC -- int)
PyObject *rc2; // secondary return code (RC2 -- string)
PyObject *result; // RESULT string
} arexxmsgobject;
struct ExecBase *AbsExecBase;
static PyObject *error; // Exception
/* Prototypes for functions defined in arexxmodule.c */
struct RexxMsg *CreateRexxCommand( struct RexxHost *host, char *buff, BPTR fh );
static void ReplyRexxCommand( struct RexxMsg *rxmsg, long prim, long sec, char *res );
static void FreeRexxCommand( struct RexxMsg *rxmsg );
static void CloseDownARexxHost( struct RexxHost *host );
static struct RexxHost *SetupARexxHost( char *basename);
static struct RexxMsg *GetARexxMsg( struct RexxHost *host );
struct RexxMsg *SendRexxCommandToPort( struct RexxHost *host,
char *port, char *cmd, BPTR fh );
static BOOL Test_Open(arexxportobject * );
static BOOL Test_Replied(arexxmsgobject * );
static PyObject * port_close(arexxportobject * , PyObject * );
static PyObject * port_wait(arexxportobject * , PyObject * );
static PyObject * port_getmsg(arexxportobject * , PyObject * );
static void port_dealloc(arexxportobject * );
static PyObject * port_getattr(arexxportobject * , unsigned char * );
static PyObject * port_repr(arexxportobject * );
static PyObject * newarexxportobject(unsigned char * );
static void msg_dealloc(arexxmsgobject * );
static PyObject * msg_getattr(arexxmsgobject * , unsigned char * );
static PyObject * msg_repr(arexxmsgobject * );
static PyObject * newarexxmsgobject(struct RexxMsg * );
static PyObject * ARexx_openport(PyObject * , PyObject * );
///*** AREXXPORT OBJECT MEMBER FUNCTIONS ***/
static BOOL Test_Open(arexxportobject *ao)
{
if(ao->host) return TRUE;
PyErr_SetString(error,"closed port");
return FALSE;
}
static PyObject *port_close(arexxportobject *ao, PyObject *args)
{
if(!PyArg_NoArgs(args)) return NULL;
if(ao->host) CloseDownARexxHost(ao->host);
ao->host=NULL;
Py_INCREF(Py_None);
return Py_None;
}
static PyObject *port_wait(arexxportobject *ao, PyObject *args)
{
if(!PyArg_NoArgs(args)) return NULL;
if(Test_Open(ao))
{
ULONG sigs = Wait(ao->signal | SIGBREAKF_CTRL_C); /* XXX Abort with ^C */
if(sigs & SIGBREAKF_CTRL_C)
{
PyErr_SetNone(KeyboardInterrupt);
return NULL;
}
Py_INCREF(Py_None);
return Py_None;
} else return NULL;
}
static PyObject *port_getmsg(arexxportobject *ao, PyObject *args)
{
if(!PyArg_NoArgs(args)) return NULL;
if(Test_Open(ao))
{
struct RexxMsg *msg;
if(msg=GetARexxMsg(ao->host))
{
return newarexxmsgobject(msg);
}
Py_INCREF(Py_None);
return Py_None;
} else return NULL;
}
static PyObject *port_send(arexxportobject *ao, PyObject *args)
{
char *to;
char *cmd;
long async;
if(!PyArg_ParseTuple(args,"ssi",&to,&cmd,&async)) return NULL;
if(Test_Open(ao))
{
struct RexxMsg *sentrm;
if( !(sentrm = SendRexxCommandToPort(ao->host, to, cmd,NULL)))
{
PyErr_SetString(error,"can't send to port");
return NULL;
}
if(!async)
{
/* wait for the reply */
PyObject *reso = NULL;
long rc;
struct RexxMsg *rm;
BOOL waiting = TRUE;
do
{
WaitPort( ao->host->port );
while( rm = (struct RexxMsg *) GetMsg(ao->host->port) )
{
/* Reply? */
if( rm->rm_Node.mn_Node.ln_Type == NT_REPLYMSG )
{
/* 'unsere' Msg? */
if( rm == sentrm )
{
rc = rm->rm_Result1;
if( !rc && rm->rm_Result2 )
{
/* Res2 is String */
reso = Py_BuildValue("(iss)",rc,NULL,rm->rm_Result2);
}
else
{
/* Res2 is number */
reso = Py_BuildValue("(iis)",rc,rm->rm_Result2,NULL);
}
waiting = FALSE;
}
FreeRexxCommand( rm );
--ao->host->replies;
}
/* sonst Kommando -> Fehler */
else if( ARG0(rm) )
{
ReplyRexxCommand( rm, -20, (long)
"invalid port", NULL );
}
}
}
while( waiting );
return reso;
}
else
{
Py_INCREF(Py_None);
return Py_None;
}
} else return NULL;
}
static struct methodlist port_methods[] = {
{"close", (method)port_close, 0},
{"getmsg", (method)port_getmsg, 0},
{"wait", (method)port_wait, 0},
{"send", (method)port_send, 1},
{NULL, NULL} /* sentinel */
};
static void
port_dealloc(arexxportobject *self) // `destructor'
{
if(self->host) CloseDownARexxHost(self->host);
PyMem_DEL(self);
}
static PyObject *
port_getattr(arexxportobject *ao, char *name)
{
if(ao->host)
{
if (strcmp(name, "name")==0)
{
if(ao->host->flags & ARB_HF_NOTPUBLIC)
{
// A non-public port doesn't have a name!
PyErr_SetString(AttributeError,name); return NULL;
}
return PyString_FromString(ao->host->portname);
}
else if(strcmp(name,"signal")==0)
return PyInt_FromLong(ao->signal);
}
return Py_FindMethod(port_methods, (PyObject *)ao, name);
}
static PyObject *
port_repr(arexxportobject *ao)
{
char buf[200];
char *w;
if(!(ao->host))
w="(closed)";
else if(ao->host->flags & ARB_HF_NOTPUBLIC)
w="(private)";
else
w=ao->host->portname;
sprintf(buf,"<arexx port %s at %lx>",w,(long)ao);
return PyString_FromString(buf);
}
static typeobject ARexxPorttype = {
OB_HEAD_INIT(&Typetype)
0, /*ob_size*/
"arexxport", /*tp_name*/
sizeof(arexxportobject), /*tp_size*/
0, /*tp_itemsize*/
/* methods */
(destructor)port_dealloc, /*tp_dealloc*/
0, /*tp_print*/
(getattrfunc)port_getattr, /*tp_getattr*/
(setattrfunc)0, /*tp_setattr*/
0, /*tp_compare*/
(reprfunc)port_repr, /*tp_repr*/
};
static PyObject *
newarexxportobject(char *name) // `constructor'
{
arexxportobject *ao;
if(name)
{
if(strlen(name)<2)
{
PyErr_SetString(ValueError,"port name too short");
return NULL;
}
(void)strupr(name);
}
if(ao = PyObject_NEW(arexxportobject, &ARexxPorttype))
{
if(ao->host=SetupARexxHost(name))
{
ao->signal = 1<<ao->host->port->mp_SigBit;
return (PyObject*)ao;
}
else PyErr_SetString(error,"can't open port");
PyMem_DEL(ao); ao=NULL;
}
return (PyObject*)ao;
}
///
///*** AREXXMSG OBJECT MEMBER FUNCTIONS ***/
static BOOL Test_Replied(arexxmsgobject *am)
{
if(am->replied)
{
PyErr_SetString(error,"already replied");
return FALSE;
}
return TRUE;
}
static PyObject *msg_reply(arexxmsgobject *am, PyObject *args)
{
if(!PyArg_NoArgs(args)) return NULL;
if(Test_Replied(am))
{
char *rc2, *result;
rc2 = PyString_Check(am->rc2)? PyString_AsString(am->rc2) : NULL;
result = PyString_Check(am->result)? PyString_AsString(am->result) : NULL;
am->rc = -am->rc; // for ReplyRexxCommand; 'rc2 is string'
ReplyRexxCommand(am->msg,am->rc,(long)rc2,result);
am->replied=TRUE;
Py_INCREF(Py_None);
return Py_None;
} else return NULL;
}
static PyObject *msg_setvar(arexxmsgobject *am, PyObject *args)
{
char *name, *val;
int vlen;
if(!PyArg_ParseTuple(args,"ss#",&name,&val,&vlen)) return NULL;
if(Test_Replied(am))
{
if(0==SetRexxVar((struct Message*)am->msg,name,val,vlen))
{
Py_INCREF(Py_None);
return Py_None;
}
else PyErr_SetString(error,"can't set var");
}
return NULL;
}
static PyObject *msg_getvar(arexxmsgobject *am, PyObject *args)
{
char *name, *val;
if(!PyArg_ParseTuple(args,"s",&name)) return NULL;
if(Test_Replied(am))
{
if(0==GetRexxVar((struct Message*)am->msg,name,&val))
{
if(val!=NULL) return PyString_FromString(val);
}
PyErr_SetString(error,"can't get var");
}
return NULL;
}
static struct methodlist msg_methods[] = {
{"reply", (method) msg_reply, 0},
{"setvar", (method) msg_setvar, 1},
{"getvar", (method) msg_getvar, 1},
{NULL, NULL} /* sentinel */
};
static void
msg_dealloc(arexxmsgobject *am) // `destructor'
{
if(!am->replied)
{
char *rc2, *result;
rc2 = PyString_Check(am->rc2)? PyString_AsString(am->rc2) : NULL;
result = PyString_Check(am->result)? PyString_AsString(am->result) : NULL;
am->rc = -am->rc; // for ReplyRexxCommand; 'rc2 is string'
ReplyRexxCommand(am->msg,am->rc,(long)rc2,result);
}
Py_DECREF(am->rc2);
Py_DECREF(am->result);
PyMem_DEL(am);
}
static PyObject *
msg_getattr(arexxmsgobject *am, char *name)
{
if (strcmp(name, "msg")==0)
return PyString_FromString(ARG0(am->msg));
if (strcmp(name, "rc")==0)
return PyInt_FromLong(am->rc);
if (strcmp(name, "rc2")==0)
{
Py_INCREF(am->rc2);
return am->rc2;
}
if (strcmp(name, "result")==0)
{
Py_INCREF(am->result);
return am->result;
}
if (strcmp(name, "wantresult")==0)
{
if( am->msg->rm_Action & RXFF_RESULT )
return PyInt_FromLong(1);
else
return PyInt_FromLong(0);
}
return Py_FindMethod(msg_methods, (PyObject *)am, name);
}
static int
msg_setattr(arexxmsgobject *am, char *name, PyObject *args)
{
if(args==NULL)
{
PyErr_SetString(AttributeError,"can't delete msg attrs"); return -1;
}
if (strcmp(name, "rc")==0)
{
if(PyInt_Check(args))
{
long rc = PyInt_AsLong(args);
if(rc>=0)
{
am->rc=rc;
}
else
{
PyErr_SetString(ValueError,"rc must be >=0"); return -1;
}
}
else
{
PyErr_SetString(TypeError,"expecting int arg"); return -1;
}
}
else if (strcmp(name, "rc2")==0)
{
if(PyString_Check(args))
{
Py_DECREF(am->rc2);
Py_INCREF(args);
am->rc2 = args;
}
else
{
PyErr_SetString(TypeError,"expecting string arg"); return -1;
}
}
else if (strcmp(name, "result")==0)
{
if(PyString_Check(args))
{
Py_DECREF(am->result);
Py_INCREF(args);
am->result = args;
}
else
{
PyErr_SetString(TypeError,"expecting string arg"); return -1;
}
}
else
{
PyErr_SetString(AttributeError,name); return -1;
}
return 0;
}
static PyObject *
msg_repr(arexxmsgobject *am)
{
char buf[100];
sprintf(buf, "<arexx msg at %lx>", (long)am);
return PyString_FromString(buf);
}
static typeobject ARexxMsgtype = {
OB_HEAD_INIT(&Typetype)
0, /*ob_size*/
"arexxmsg", /*tp_name*/
sizeof(arexxmsgobject), /*tp_size*/
0, /*tp_itemsize*/
/* methods */
(destructor)msg_dealloc, /*tp_dealloc*/
0, /*tp_print*/
(getattrfunc)msg_getattr, /*tp_getattr*/
(setattrfunc)msg_setattr, /*tp_setattr*/
0, /*tp_compare*/
(reprfunc)msg_repr, /*tp_repr*/
};
static PyObject *
newarexxmsgobject(struct RexxMsg *msg) // `constructor'
{
arexxmsgobject *am;
if(am = PyObject_NEW(arexxmsgobject, &ARexxMsgtype))
{
am->msg=msg;
am->rc=0;
Py_INCREF(Py_None); am->rc2=Py_None;
Py_INCREF(Py_None); am->result=Py_None;
am->replied=FALSE;
}
return (PyObject*)am;
}
///
///******************************* AREXX SUPPORT FUNCTIONS *******************/
struct RexxMsg *CreateRexxCommand( struct RexxHost *host, char *buff, BPTR fh )
{
struct RexxMsg *rexx_command_message;
if( (rexx_command_message = CreateRexxMsg( host->port,
"python", host->port->mp_Node.ln_Name)) == NULL )
{
return( NULL );
}
if( (rexx_command_message->rm_Args[0] =
CreateArgstring(buff,strlen(buff))) == NULL )
{
DeleteRexxMsg(rexx_command_message);
return( NULL );
}
rexx_command_message->rm_Action = RXCOMM | RXFF_RESULT;
rexx_command_message->rm_Stdin = fh;
rexx_command_message->rm_Stdout = fh;
return( rexx_command_message );
}
static void ReplyRexxCommand(
struct RexxMsg *rexxmessage,
long primary,
long secondary,
char *result )
{
if( rexxmessage->rm_Action & RXFF_RESULT )
{
if( primary == 0 )
{
secondary = result
? (long) CreateArgstring( result, strlen(result) )
: (long) NULL;
}
else
{
char buf[16];
if( primary > 0 )
{
sprintf( buf, "%ld", secondary );
result = buf;
}
else
{
primary = -primary;
result = (char *) secondary;
}
SetRexxVar( (struct Message *) rexxmessage,
"RC2", result, strlen(result) );
secondary = 0;
}
}
else if( primary < 0 )
primary = -primary;
rexxmessage->rm_Result1 = primary;
rexxmessage->rm_Result2 = secondary;
ReplyMsg( (struct Message *) rexxmessage );
}
static void FreeRexxCommand( struct RexxMsg *rexxmessage )
{
if( !rexxmessage->rm_Result1 && rexxmessage->rm_Result2 )
DeleteArgstring( (char *) rexxmessage->rm_Result2 );
if( rexxmessage->rm_Stdin &&
rexxmessage->rm_Stdin != Input() )
Close( rexxmessage->rm_Stdin );
if( rexxmessage->rm_Stdout &&
rexxmessage->rm_Stdout != rexxmessage->rm_Stdin &&
rexxmessage->rm_Stdout != Output() )
Close( rexxmessage->rm_Stdout );
DeleteArgstring( (char *) ARG0(rexxmessage) );
DeleteRexxMsg( rexxmessage );
}
static void CloseDownARexxHost( struct RexxHost *host )
{
struct RexxMsg *rexxmsg;
if( host->port )
{
/* Port abmelden */
if(!(host->flags & ARB_HF_NOTPUBLIC))
RemPort( host->port );
/* Auf noch ausstehende Replies warten */
while( host->replies > 0 )
{
WaitPort( host->port );
while( rexxmsg = (struct RexxMsg *) GetMsg(host->port) )
{
if( rexxmsg->rm_Node.mn_Node.ln_Type == NT_REPLYMSG )
{
FreeRexxCommand( rexxmsg );
--host->replies;
}
else
ReplyRexxCommand( rexxmsg, -20, (long) "Host closing down", NULL );
}
}
/* MsgPort leeren */
while( rexxmsg = (struct RexxMsg *) GetMsg(host->port) )
ReplyRexxCommand( rexxmsg, -20, (long) "Host closing down", NULL );
// if( !(host->flags & ARB_HF_USRMSGPORT) )
DeleteMsgPort( host->port );
}
free( host );
}
// static struct RexxHost *SetupARexxHost( char *basename, struct MsgPort *usrport )
static struct RexxHost *SetupARexxHost( char *basename)
{
struct RexxHost *host;
int ext = 0;
if( !(host = calloc(sizeof *host, 1)) )
return NULL;
if(basename) strcpy( host->portname, basename );
else host->flags |= ARB_HF_NOTPUBLIC;
if( !(host->port = CreateMsgPort()) )
{
free( host );
return NULL;
}
else
{
host->port->mp_Node.ln_Pri = 0;
}
if(!(host->flags & ARB_HF_NOTPUBLIC))
{
Forbid();
while( FindPort(host->portname) )
sprintf( host->portname, "%s.%d", basename, ++ext );
host->port->mp_Node.ln_Name = host->portname;
AddPort( host->port );
Permit();
}
return( host );
}
/* GetARexxMsg:
** returns the RexxMsg that is waiting at the port,
** or NULL if no message is present.
*/
static struct RexxMsg *GetARexxMsg( struct RexxHost *host )
{
struct RexxMsg *rexxmsg;
while( rexxmsg = (struct RexxMsg *) GetMsg(host->port) )
{
if( (rexxmsg->rm_Action & RXCODEMASK) != RXCOMM )
{
/* Keine Rexx-Message */
ReplyMsg( (struct Message *) rexxmsg );
}
else if( rexxmsg->rm_Node.mn_Node.ln_Type == NT_REPLYMSG )
{
struct RexxMsg *org = (struct RexxMsg *) rexxmsg->rm_Args[15];
if( org )
{
/* Reply zu durchgereichter Msg */
if( rexxmsg->rm_Result1 != 0 )
{
/* Befehl unbekannt */
ReplyRexxCommand( org, 20, ERROR_NOT_IMPLEMENTED, NULL );
}
else
{
ReplyRexxCommand( org, 0, 0, (char *) rexxmsg->rm_Result2 );
}
}
FreeRexxCommand( rexxmsg );
--host->replies;
}
else if( ARG0(rexxmsg) )
{
return rexxmsg; /* return the ARexx message! */
}
else
{
ReplyMsg( (struct Message *) rexxmsg );
}
}
return NULL; /* no important message arrived. */
}
struct RexxMsg *SendRexxCommandToPort( struct RexxHost *host, char *port, char *cmd, BPTR fh )
{
struct RexxMsg *rcm;
if( rcm = CreateRexxCommand(host, cmd, fh) )
{
struct MsgPort *rexxport;
Forbid();
if( (rexxport = FindPort(port)) == NULL )
{
Permit();
return( NULL );
}
PutMsg( rexxport, &rcm->rm_Node );
Permit();
++host->replies;
return( rcm );
}
else
return NULL;
}
///
///******************************** MODULE FUNCTIONS ************************/
static PyObject *
ARexx_openport(PyObject *self, PyObject *args)
{
PyObject *p=NULL;
if (!PyArg_ParseTuple(args, "|O", &p))
return NULL;
if(!p)
return newarexxportobject("PYTHON");
else if(p==Py_None)
/* open anonymous port (only for sending) */
return newarexxportobject(NULL);
else if(PyString_Check(p))
return newarexxportobject(PyString_AsString(p));
else
return (PyObject*)PyErr_BadArgument();
}
static PyObject *
ARexx_errorstring(PyObject *self, PyObject *args)
{
/* undocumented function: */
extern BOOL ErrorMsg(LONG err);
#pragma libcall RexxSysBase ErrorMsg 60 001
long err;
if (!PyArg_ParseTuple(args, "i", &err))
return NULL;
if(ErrorMsg(err))
{
struct NexxStr *s = (struct NexxStr*)getreg(REG_A0);
return PyString_FromStringAndSize(&s->ns_Buff[0],s->ns_Length);
}
else
{
PyErr_SetString(ValueError,"invalid error code");
return NULL;
}
}
/*** FUNCTIONS FROM THE MODULE ***/
static struct methodlist ARexx_global_methods[] = {
{"port", ARexx_openport, 1},
{"errorstring", ARexx_errorstring, 1},
{NULL, NULL} /* sentinel */
};
///
void
initarexx Py_PROTO((void))
{
PyObject *m, *d;
AbsExecBase = *(struct ExecBase**)4;
m = Py_InitModule("arexxll", ARexx_global_methods);
d = PyModule_GetDict(m);
/* Initialize error exception */
error = PyString_FromString("arexx.error");
if (error == NULL || PyDict_SetItemString(d, "error", error) != 0)
Py_FatalError("can't define arexxll.error");
}